home *** CD-ROM | disk | FTP | other *** search
Text File | 2002-08-14 | 67.7 KB | 2,360 lines |
- Index: linux/Documentation/filesystems/supermount.txt
- diff -u linux/Documentation/filesystems/supermount.txt:1.1 linux/Documentation/filesystems/supermount.txt:1.1.6.1
- --- linux/Documentation/filesystems/supermount.txt:1.1 Mon Feb 26 17:55:03 1996
- +++ linux/Documentation/filesystems/supermount.txt Sat Nov 9 20:35:00 1996
- @@ -0,0 +1,179 @@
- +Supermount README
- +=================
- +
- +For supermount v0.4c, on linux kernels 2.0.23 or later.
- +
- +Supermount is a pseudo-filesystem which manages filesystems on
- +removable media like floppy disks and CD-ROMs. It aims to make
- +management of removable media as easy as it is under DOS.
- +
- +With supermount, you can change the disk in the drive whenever you
- +want (with the obvious exception that you shouldn't do it when the
- +filesystem is actively in use). You don't need to "cd" out of the
- +directory first, and you don't need to tell the kernel what you're
- +doing --- supermount will detect the media change automatically.
- +
- +Supermount will automatically detect whether the media you are
- +mounting is read-write or readonly, and if you mount a write-protected
- +disk, then the subfs will be mounted as a readonly filesystem.
- +
- +Supermount detects when you have finished activity on the subfs, and
- +will flush all buffers to the disk before completing the operation.
- +So, if you copy a file onto a supermounted floppy disk, the data will
- +all be written to disk before the "cp" command finishes. When the
- +command does complete, it will be safe to remove the disk.
- +
- +It is worth while defining what I mean by "activity" here. The subfs
- +is active if there are any processes running which have a handle on a
- +non-directory inode on the subfs, or which have a file open on the
- +subfs (even if only for reading). There is one important case which
- +does NOT count as activity: if you "cd" to a directory or a
- +subdirectory under the supermount mount point, then that reference
- +does not make the subfs active, and you can safely remove the disk.
- +
- +Yes, that's right. You can "cd /floppy; ls" and get a listing of a
- +dos floppy. Remove the disk, insert a new one, and "ls" will now list
- +the new contents. Remove the disk altogether, and "ls" will give you
- +an I/O error. Put in a new disk, and "ls" starts working again. It
- +is NOT an error to remove a supermounted disk which is acting as the
- +current working directory for one or more processes!
- +
- +
- +The Superfilesystem and Subfilesystem concepts
- +----------------------------------------------
- +
- +Normally, when you mount a filesystem, you create a direct connection
- +between a mount point in the directory tree and a filesystem on a
- +block device. Supermount adds an extra layer in between; with
- +supermount, you explicitly mount the pseudo-filesystem (the
- +"superfilesystem") on the mount point, and supermount then
- +automatically mounts the real filesystem (the "subfilesystem") on the
- +block device when needed.
- +
- +Running supermount
- +------------------
- +
- +To run supermount, compile and install a kernel with the supermount
- +patches and select "Y" to the question
- +
- + Dynamic mounting of removable media?
- +
- +when you run "make config". You set up a supermount filesystem with
- +the normal mount command, using the syntax:
- +
- + mount -o <superfs-options>,--,<subfs-options> <dev> <mount-point>
- +
- +<dev> can be anything you want. Using supermount, the block device
- +you are using is not physically mounted until there is a filesystem
- +access to the mount point, so the device specified on the command line
- +is ignored. It is convenient just to specify the mount point as the
- +device as well, so that you give the mount point twice on the command
- +line. Doing this reduces the chance that the mount program will
- +confuse the mount point with some other mount point defined in
- +/etc/fstab.
- +
- +The way you specify the location of the block device you want to mount
- +is by providing the <superfs-options> field, where the following
- +options are currently recognised:
- +
- +* subfs=<filesystem-type> [default is "msdos"]
- +
- + Specify the subfilesystem type. "msdos" and "iso9660" have
- +been tested, but any block-device filesystem should work with one
- +important restriction: the filesystem must NOT try to write to the
- +device when you unmount it. This is because supermount doesn't know
- +in advance when it will have to unmount the subfs, so it doesn't try
- +to do so until it detects that the media has been changed. By this
- +time it is too late to write to the device!
- +
- + If you mount supermount as a readonly filesystem ("mount -r"
- +or "mount -o ro"), then you won't have this problem. Otherwise, you
- +will not be able to use the ext2fs or minix filesystems with
- +supermount. This will hopefully be addressed in a future release of
- +supermount.
- +
- +* dev=<block-device> [default is "/dev/fd0"]
- +
- + Specify the block device on which the subfs is to be mounted.
- +
- +* debug
- +
- + Enable debugging code in the supermount filesystem, if
- +the debug option was enabled at compile time. By default, debugging
- +code is compiled into the kernel but is disabled until a debug mount
- +option is seen.
- +
- +* '--'
- +
- + All options after the option string '--' will be passed
- +directly to the subfilesystem when it gets mounted.
- +
- +
- +Here is an example of supermount options, taken directly out of my
- +current /etc/fstab:
- +
- +/floppy /floppy supermount --,gid=51,conv=binary 0 0
- +/cd /cd supermount ro,fs=iso9660,dev=/dev/hdd,--,conv=binary 0 0
- +
- +This tells supermount to manage a msdos filesystem on /dev/fd0 mounted
- +at /floppy (msdos and /dev/fd0 are defaults for supermount), with the
- +msdos filesystem getting the options "gid=51,conv=binary". My cdrom
- +on /dev/hdd is similarly mounted on /cd.
- +
- +
- +Caveats and Provisos
- +--------------------
- +
- +There are still some limitations to the current version of
- +supermount. I hope to overcome these shortly in future releases, but
- +for now, be aware that:
- +
- +* You can only specify one filesystem type on the mount command line.
- + Supermount cannot yet autodetect the type of filesystem you supply.
- +
- +* With the 2.0 kernel, CDROM door locking has been made much more
- + aggressive. You will probably find that once supermount has mounted
- + your disk, you cannot unmount it again. Not helpful!
- +
- +* The only filesystem which is supported read/write with supermount is
- + msdos. The msdos filesystem has the special characteristic that it
- + never has to access the disk when you unmount it, so supermount can
- + safely defer the unmounting until after the disk is removed. That
- + doesn't work so well for filesystems such as ext2fs which try to
- + write to the filesystem when it is unmounted.
- +
- +Problems 2) and 3) are being solved by a development patch to support
- +unmount-on-timeout, which will do a full unmount of the media after
- +half a second or so of inactivity, releasing the volume for removal.
- +Problem 1) has been addressed by a contributed patch which I hope to
- +integrate shortly. As usual, watch this space, and anybody who I've
- +got on my list of supermount users will be emailed with further
- +developments!
- +
- +
- +Enjoy supermount. I hope you find it useful --- I certainly find it
- +extremely convenient. Send any comments, bug-fixes or bug-reports,
- +suggestions and success stories to sct@dcs.ed.ac.uk. Flames to
- +/dev/null, please!
- +
- +Cheers,
- + Stephen.
- +--
- +
- +================================================================
- +Changes for v0.4c:
- +Works against linux-2.0.23.
- +Updated documentation.
- +Fixed problem with default root inode mode.
- +
- +Changes for v0.4:
- +Performance tuning only. Read-only operations like "find" should now
- +be MUCH faster.
- +
- +Changes for v0.3:
- +Fixed supermount_create bug; now returns a properly attached
- +superinode.
- +
- +Changes for v0.2:
- +Improved device invalidation code, so CD-ROMs work now.
- +
- Index: linux/fs/Config.in
- diff -u linux/fs/Config.in:1.5 linux/fs/Config.in:1.5.2.1
- --- linux/fs/Config.in:1.5 Wed Nov 6 23:16:50 1996
- +++ linux/fs/Config.in Sat Nov 9 17:26:20 1996
- @@ -6,6 +6,7 @@
-
- bool 'Quota support' CONFIG_QUOTA
- bool 'Mandatory lock support' CONFIG_LOCK_MANDATORY
- +bool 'Supermount removable media support' CONFIG_SUPERMOUNT
- tristate 'Minix fs support' CONFIG_MINIX_FS
- tristate 'Extended fs support' CONFIG_EXT_FS
- tristate 'Second extended fs support' CONFIG_EXT2_FS
- Index: linux/fs/Makefile
- diff -u linux/fs/Makefile:1.4 linux/fs/Makefile:1.4.4.1
- --- linux/fs/Makefile:1.4 Wed May 15 14:12:18 1996
- +++ linux/fs/Makefile Sat Nov 9 17:26:21 1996
- @@ -17,7 +17,7 @@
-
- MOD_LIST_NAME := FS_MODULES
- ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \
- - hpfs sysv smbfs ncpfs ufs affs
- + hpfs sysv smbfs ncpfs ufs affs supermount
-
- ifeq ($(CONFIG_QUOTA),y)
- O_OBJS += dquot.o
- @@ -139,6 +139,14 @@
- ifeq ($(CONFIG_HPFS_FS),m)
- MOD_SUB_DIRS += hpfs
- endif
- +endif
- +
- +ifeq ($(CONFIG_SUPERMOUNT),y)
- +SUB_DIRS += supermount
- +#else
- +# ifeq ($(CONFIG_SUPERMOUNT),m)
- +# MOD_SUB_DIRS += supermount
- +# endif
- endif
-
- ifeq ($(CONFIG_UFS_FS),y)
- Index: linux/fs/devices.c
- diff -u linux/fs/devices.c:1.3 linux/fs/devices.c:1.3.4.1
- --- linux/fs/devices.c:1.3 Wed May 15 14:12:20 1996
- +++ linux/fs/devices.c Sat Nov 9 17:26:22 1996
- @@ -187,15 +187,14 @@
- }
-
- /*
- - * This routine checks whether a removable media has been changed,
- - * and invalidates all buffer-cache-entries in that case. This
- - * is a relatively slow routine, so we have to try to minimize using
- - * it. Thus it is called only upon a 'mount' or 'open'. This
- - * is the best way of combining speed and utility, I think.
- - * People changing diskettes in the middle of an operation deserve
- - * to loose :-)
- - */
- -int check_disk_change(kdev_t dev)
- + * These routines checks whether a removable media has been changed,
- + * and (for check_disk_change only) invalidate all
- + * buffer-cache-entries in that case. This is a relatively slow
- + * routine, so we have to try to minimize using it. Thus it is called
- + * only upon a 'mount' or 'open'. This is the best way of combining
- + * speed and utility, I think. People changing diskettes in the
- + * middle of an operation deserve to loose :-) */
- +int query_disk_change(kdev_t dev)
- {
- int i;
- struct file_operations * fops;
- @@ -208,17 +207,37 @@
- if (!fops->check_media_change(dev))
- return 0;
-
- + return 1;
- +}
- +
- +int check_disk_change(kdev_t dev)
- +{
- + if (!query_disk_change(dev))
- + return 0;
- printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
- kdevname(dev));
- + invalidate_media(dev);
- + return 1;
- +}
- +
- +void invalidate_media(kdev_t dev)
- +{
- + int i;
- + struct file_operations * fops;
- +
- + i = MAJOR(dev);
- + if (i >= MAX_BLKDEV)
- + return;
- + fops = blkdevs[i].fops;
- for (i=0 ; i<NR_SUPER ; i++)
- if (super_blocks[i].s_dev == dev)
- put_super(super_blocks[i].s_dev);
- invalidate_inodes(dev);
- invalidate_buffers(dev);
-
- - if (fops->revalidate)
- + if (fops && fops->revalidate)
- fops->revalidate(dev);
- - return 1;
- + return;
- }
-
- /*
- Index: linux/fs/filesystems.c
- diff -u linux/fs/filesystems.c:1.3 linux/fs/filesystems.c:1.3.4.1
- --- linux/fs/filesystems.c:1.3 Sat Apr 27 17:06:29 1996
- +++ linux/fs/filesystems.c Sat Nov 9 17:26:22 1996
- @@ -9,6 +9,7 @@
- #include <linux/config.h>
- #include <linux/fs.h>
-
- +#include <linux/supermount_fs.h>
- #include <linux/minix_fs.h>
- #include <linux/ext_fs.h>
- #include <linux/ext2_fs.h>
- @@ -39,6 +40,11 @@
- callable = 0;
-
- device_setup();
- +
- +#ifdef CONFIG_SUPERMOUNT
- + register_filesystem(&(struct file_system_type)
- + {supermount_read_super, "supermount", 0, NULL});
- +#endif
-
- binfmt_setup();
-
- Index: linux/fs/inode.c
- diff -u linux/fs/inode.c:1.5 linux/fs/inode.c:1.5.2.1
- --- linux/fs/inode.c:1.5 Wed Nov 6 23:16:52 1996
- +++ linux/fs/inode.c Sat Nov 9 17:26:22 1996
- @@ -219,6 +219,8 @@
- if (inode == mount_root && inode->i_count ==
- (inode->i_mount != inode ? 1 : 2))
- continue;
- + if (IS_UNBOUND(inode))
- + continue;
- return 0;
- }
- return 1;
- @@ -254,6 +256,9 @@
- inode->i_lock = 1;
- inode->i_sb->s_op->write_inode(inode);
- unlock_inode(inode);
- + if (inode->i_shadow && inode->i_shadow->i_shadow_op &&
- + inode->i_shadow->i_shadow_op->write)
- + inode->i_shadow->i_shadow_op->write(inode->i_shadow);
- }
-
- static inline void read_inode(struct inode * inode)
- @@ -414,15 +419,24 @@
- }
- }
-
- +static inline void release_shadow(struct inode * inode) {
- + /* Shadow-release should be atomic. */
- + struct inode * tmp;
- + tmp = inode->i_shadow;
- + inode->i_shadow = 0;
- +}
- +
- void iput(struct inode * inode)
- {
- + struct inode * shadow;
- +
- if (!inode)
- return;
- wait_on_inode(inode);
- if (!inode->i_count) {
- printk("VFS: iput: trying to free free inode\n");
- printk("VFS: device %s, inode %lu, mode=0%07o\n",
- - kdevname(inode->i_rdev), inode->i_ino, inode->i_mode);
- + kdevname(inode->i_dev), inode->i_ino, inode->i_mode);
- return;
- }
- if (inode->i_pipe)
- @@ -441,9 +455,22 @@
- }
-
- if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
- + shadow = inode->i_shadow;
- inode->i_sb->s_op->put_inode(inode);
- - if (!inode->i_nlink)
- + if (!inode->i_nlink) {
- + /* The inode should have been cleared, so we
- + don't reset inode->i_shadow here. */
- + if (shadow) {
- + if (shadow->i_shadow_op &&
- + shadow->i_shadow_op->release)
- + shadow->i_shadow_op->release(shadow);
- + iput (shadow);
- + }
- + /* put_inode should do a clear_inode() if the
- + inode is unlinked, so don't bother falling
- + through... */
- return;
- + }
- }
-
- if (inode->i_dirt) {
- @@ -473,6 +500,14 @@
- }
-
- nr_free_inodes++;
- + shadow = inode->i_shadow;
- + inode->i_shadow = 0;
- + if (shadow) {
- + if (shadow->i_shadow_op &&
- + shadow->i_shadow_op->release)
- + shadow->i_shadow_op->release(shadow);
- + iput (shadow);
- + }
- return;
- }
-
- Index: linux/fs/open.c
- diff -u linux/fs/open.c:1.4 linux/fs/open.c:1.4.2.1
- --- linux/fs/open.c:1.4 Wed Nov 6 23:16:53 1996
- +++ linux/fs/open.c Sat Nov 9 17:26:22 1996
- @@ -523,6 +523,10 @@
- goto cleanup_inode;
- }
-
- + if (inode->i_shadow && inode->i_shadow->i_shadow_op &&
- + inode->i_shadow->i_shadow_op->open)
- + inode->i_shadow->i_shadow_op->open(inode->i_shadow, flag);
- +
- f->f_inode = inode;
- f->f_pos = 0;
- f->f_reada = 0;
- Index: linux/fs/super.c
- diff -u linux/fs/super.c:1.9 linux/fs/super.c:1.9.2.1
- --- linux/fs/super.c:1.9 Wed Nov 6 23:16:54 1996
- +++ linux/fs/super.c Sat Nov 9 17:26:23 1996
- @@ -628,21 +628,12 @@
- * functions, they should be faked here. -- jrs
- */
-
- -asmlinkage int sys_umount(char * name)
- +int do_umounti(struct inode * inode)
- {
- - struct inode * inode;
- kdev_t dev;
- int retval;
- struct inode dummy_inode;
-
- - if (!suser())
- - return -EPERM;
- - retval = namei(name, &inode);
- - if (retval) {
- - retval = lnamei(name, &inode);
- - if (retval)
- - return retval;
- - }
- if (S_ISBLK(inode->i_mode)) {
- dev = inode->i_rdev;
- if (IS_NODEV(inode)) {
- @@ -681,50 +672,55 @@
- return 0;
- }
-
- -/*
- - * do_mount() does the actual mounting after sys_mount has done the ugly
- - * parameter parsing. When enough time has gone by, and everything uses the
- - * new mount() parameters, sys_mount() can then be cleaned up.
- +asmlinkage int sys_umount(char * name)
- +{
- + struct inode * inode;
- + int retval;
- +
- + if (!suser())
- + return -EPERM;
- + retval = namei(name,&inode);
- + if (retval) {
- + retval = lnamei(name,&inode);
- + if (retval)
- + return retval;
- + }
- + return do_umounti(inode);
- +}
- +
- +/*
- + * do_mountdev() does the actual mounting after sys_mount has done the
- + * ugly parameter parsing. When enough time has gone by, and
- + * everything uses the new mount() parameters, sys_mount() can then be
- + * cleaned up.
- *
- * We cannot mount a filesystem if it has active, used, or dirty inodes.
- * We also have to flush all inode-data for this device, as the new mount
- - * might need new info.
- + * might need new info.
- */
-
- -int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
- +int do_mountdev(kdev_t dev,
- + struct inode *dir_i,
- + const char * dev_name,
- + const char * dir_name,
- + const char * type,
- + int flags,
- + void * data)
- {
- - struct inode * dir_i;
- struct super_block * sb;
- struct vfsmount *vfsmnt;
- - int error;
-
- - if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
- - return -EACCES;
- - /*flags |= MS_RDONLY;*/
- - error = namei(dir_name, &dir_i);
- - if (error)
- - return error;
- - if (dir_i->i_count != 1 || dir_i->i_mount) {
- - iput(dir_i);
- + if (dir_i->i_count != 1 || dir_i->i_mount)
- return -EBUSY;
- - }
- - if (!S_ISDIR(dir_i->i_mode)) {
- - iput(dir_i);
- + if (!S_ISDIR(dir_i->i_mode))
- return -ENOTDIR;
- - }
- - if (!fs_may_mount(dev)) {
- - iput(dir_i);
- + if (!fs_may_mount(dev))
- return -EBUSY;
- - }
- sb = read_super(dev,type,flags,data,0);
- - if (!sb) {
- - iput(dir_i);
- + if (!sb)
- return -EINVAL;
- - }
- - if (sb->s_covered) {
- - iput(dir_i);
- + if (sb->s_covered)
- return -EBUSY;
- - }
- vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
- if (vfsmnt) {
- vfsmnt->mnt_sb = sb;
- @@ -736,6 +732,26 @@
- }
-
-
- +int do_mount(kdev_t dev,
- + const char * dev_name,
- + const char * dir_name,
- + const char * type,
- + int flags,
- + void * data)
- +{
- + int error;
- + struct inode * dir_i;
- +
- + error = namei(dir_name, &dir_i);
- + if (error)
- + return error;
- + error = do_mountdev(dev, dir_i, dev_name, dir_name, type, flags, data);
- + if (error)
- + iput(dir_i);
- + return error;
- +}
- +
- +
- /*
- * Alters the mount flags of a mounted file system. Only the mount point
- * is used as a reference - file system type and the device are ignored.
- @@ -794,14 +810,23 @@
- if (!data)
- return 0;
-
- - vma = find_vma(current->mm, (unsigned long) data);
- - if (!vma || (unsigned long) data < vma->vm_start)
- - return -EFAULT;
- - if (!(vma->vm_flags & VM_READ))
- - return -EFAULT;
- - i = vma->vm_end - (unsigned long) data;
- - if (PAGE_SIZE <= (unsigned long) i)
- + /*
- + * Supermount calls the mount code from kernel space, so don't
- + * validate the mount data if it is already in kernel address
- + * space.
- + */
- + if (get_fs() != get_ds()) {
- + vma = find_vma(current->mm, (unsigned long) data);
- + if (!vma || (unsigned long) data < vma->vm_start)
- + return -EFAULT;
- + if (!(vma->vm_flags & VM_READ))
- + return -EFAULT;
- + i = vma->vm_end - (unsigned long) data;
- + if (PAGE_SIZE <= (unsigned long) i)
- + i = PAGE_SIZE-1;
- + } else {
- i = PAGE_SIZE-1;
- + }
- if (!(page = __get_free_page(GFP_KERNEL))) {
- return -ENOMEM;
- }
- @@ -825,15 +850,10 @@
- * version that didn't understand them.
- */
- asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
- - unsigned long new_flags, void * data)
- + unsigned long new_flags, void * data)
- {
- - struct file_system_type * fstype;
- - struct inode * inode;
- - struct file_operations * fops;
- - kdev_t dev;
- + struct inode * dir_inode;
- int retval;
- - const char * t;
- - unsigned long flags = 0;
- unsigned long page = 0;
-
- if (!suser())
- @@ -849,6 +869,29 @@
- free_page(page);
- return retval;
- }
- + retval = namei(dir_name, &dir_inode);
- + if (retval)
- + return retval;
- + retval = do_mounti(dir_inode,dir_name,dev_name,type,new_flags,data);
- + if (retval)
- + iput(dir_inode);
- + return retval;
- +}
- +
- +/* Mount on a given inode. Don't iput() the mount point! */
- +int do_mounti(struct inode * dir_inode, const char * dir_name,
- + const char * dev_name, const char * type,
- + unsigned long new_flags, const void * data)
- +{
- + struct file_system_type * fstype;
- + struct inode * inode;
- + struct file_operations * fops;
- + dev_t dev;
- + int retval;
- + const char * t;
- + unsigned long flags = 0;
- + unsigned long page = 0;
- +
- retval = copy_mount_options (type, &page);
- if (retval < 0)
- return retval;
- @@ -906,7 +949,8 @@
- return retval;
- }
- }
- - retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
- + retval = do_mountdev(dev,dir_inode,dev_name,dir_name,
- + t,flags,(void *) page);
- free_page(page);
- if (retval && fops && fops->release)
- fops->release(inode, NULL);
- Index: linux/fs/supermount/Makefile
- diff -u linux/fs/supermount/Makefile:1.1 linux/fs/supermount/Makefile:1.1.6.1
- --- linux/fs/supermount/Makefile:1.1 Mon Feb 26 17:55:15 1996
- +++ linux/fs/supermount/Makefile Sat Nov 9 17:27:24 1996
- @@ -0,0 +1,14 @@
- +#
- +# Makefile for the linux supermounting routines.
- +#
- +# Note! Dependencies are done automagically by 'make dep', which also
- +# removes any old dependencies. DON'T put your own dependencies here
- +# unless it's something special (ie not a .c file).
- +#
- +# Note 2! The CFLAGS definitions are now in the main makefile...
- +
- +O_TARGET := supermount.o
- +O_OBJS := dir.o inode.o namei.o super.o
- +M_OBJS := $(O_TARGET)
- +
- +include $(TOPDIR)/Rules.make
- Index: linux/fs/supermount/TODO
- diff -u linux/fs/supermount/TODO:1.1 linux/fs/supermount/TODO:1.1.6.1
- --- linux/fs/supermount/TODO:1.1 Mon Feb 26 17:55:15 1996
- +++ linux/fs/supermount/TODO Sat Nov 9 17:27:24 1996
- @@ -0,0 +1,40 @@
- +Notes:
- +
- +TODO:
- +
- + Supermount directory inodes do auto-remount as root of the subfs. Make
- + a mount option to restrict this behaviour to the root?
- +
- + Make supermount_attach a special case of read_hidden_inode, not the other
- + way around.
- +
- + Replace shadow inodes with shadow superblock? Do release that way?
- +
- + Unmount on suspend? OK iff inode numbers on open directories will
- + be the same next time around! (Normally true.) Bad for performance, but
- + maybe necessary for ext2fs, for example.
- +
- +Done:::
- +
- + Sigh. We can't rely on the one-to-one mapping of superinode to
- + subinode i_ino numbers any more. Why not? Well, what happens if we
- + remove and remount a medium? We can end up with one process holding
- + a handle to an old, obsolete superinode, and a new process opening a
- + subinode with the same i_ino. Well, we can do a quadratic hash on
- + the superinode numbers to avoid collisions. Think about this!
- +
- + * What happens when we do get an inode collision? We rehash to make
- + another superinode the current one; the old inode remains as a
- + placeholder. But then, what if the old inode becomes released? A
- + subsequent attach may place the subinode under that old inode
- + instead of the new superinode.
- +
- + OK: There is only ever one hidden/shadow connection between super
- + and sub inodes. If that is broken, we can reestablish it from any
- + superinode we want to. Previously valid superinodes will have to
- + rely on i_subino to get to their subinode (the subinode i_ino will
- + NOT change behind our backs, hopefully). Such mappings should
- + only ever be one way, from superinode to subinode, done by
- + subiget().
- +
- + Special handling of root directory to do auto remount.
- Index: linux/fs/supermount/dir.c
- diff -u linux/fs/supermount/dir.c:1.1 linux/fs/supermount/dir.c:1.1.6.1
- --- linux/fs/supermount/dir.c:1.1 Mon Feb 26 17:55:15 1996
- +++ linux/fs/supermount/dir.c Sat Nov 9 17:27:24 1996
- @@ -0,0 +1,97 @@
- +/*
- + * linux/fs/supermount/dir.c
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + * from
- + *
- + * linux/fs/minix/dir.c
- + * Copyright (C) 1991, 1992 Linus Torvalds
- + *
- + * and
- + *
- + * linux/fs/ext2/dir.c
- + * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
- + */
- +
- +#include <asm/segment.h>
- +
- +#include <linux/errno.h>
- +#include <linux/kernel.h>
- +#include <linux/fs.h>
- +#include <linux/supermount_fs.h>
- +#include <linux/stat.h>
- +
- +static int supermount_dir_open (struct inode *, struct file *);
- +
- +static struct file_operations supermount_dir_operations = {
- + NULL, /* lseek - default */
- + NULL, /* read */
- + NULL, /* write - bad */
- + NULL, /* readdir */
- + NULL, /* select - default */
- + NULL, /* ioctl */
- + NULL, /* mmap */
- + supermount_dir_open, /* Redirect to the subfs readdir() code */
- + NULL, /* no special release code */
- + NULL, /* fsync */
- + NULL, /* fasync */
- + NULL, /* check_media_change */
- + NULL /* revalidate */
- +};
- +
- +/*
- + * directories can handle most operations... supermount/namei.c just
- + * passes them through to the underlying subfs, except for lookup().
- + */
- +struct inode_operations supermount_dir_iops = {
- + &supermount_dir_operations, /* default directory file-ops */
- + supermount_create, /* create */
- + supermount_lookup, /* lookup */
- + supermount_link, /* link */
- + supermount_unlink, /* unlink */
- + supermount_symlink, /* symlink */
- + supermount_mkdir, /* mkdir */
- + supermount_rmdir, /* rmdir */
- + supermount_mknod, /* mknod */
- + supermount_rename, /* rename */
- + NULL, /* readlink */
- + NULL, /* follow_link */
- + NULL, /* bmap */
- + NULL, /* truncate */
- + supermount_permission, /* permission */
- + NULL /* smap */
- +};
- +
- +
- +/* When we open() a directory (for readdir), just rewrite the file
- + struct to point to the subfs inode, and let it handle all the
- + work. */
- +static int supermount_dir_open (struct inode * inode, struct file * file)
- +{
- + struct inode * subi;
- + int rc;
- +
- + if (file->f_mode & 2)
- + return -EPERM;
- +
- + supermount_debug ("dir_open inode %ld\n", inode->i_ino);
- +
- + subi = subiget(inode);
- + if (!subi)
- + return -ENOENT;
- +
- + file->f_inode = subi;
- + file->f_op = subi->i_op ? subi->i_op->default_file_ops : NULL;
- + if (file->f_op && file->f_op->open) {
- + rc = file->f_op->open(subi, file);
- + if (rc) {
- + iput(subi);
- + return rc;
- + }
- + }
- + iput(inode);
- + return 0;
- +}
- +
- Index: linux/fs/supermount/file.c
- diff -u linux/fs/supermount/file.c:1.1 linux/fs/supermount/file.c:1.1.6.1
- --- linux/fs/supermount/file.c:1.1 Mon Feb 26 17:55:15 1996
- +++ linux/fs/supermount/file.c Sat Nov 9 17:27:25 1996
- @@ -0,0 +1,21 @@
- +/*
- + * linux/fs/supermount/file.c
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + */
- +
- +#include <asm/segment.h>
- +#include <asm/system.h>
- +
- +#include <linux/errno.h>
- +#include <linux/fs.h>
- +#include <linux/supermount_fs.h>
- +#include <linux/fcntl.h>
- +#include <linux/sched.h>
- +#include <linux/stat.h>
- +#include <linux/locks.h>
- +
- +static void supermount_inode_release (struct inode *);
- +
- Index: linux/fs/supermount/inode.c
- diff -u linux/fs/supermount/inode.c:1.1 linux/fs/supermount/inode.c:1.1.6.1
- --- linux/fs/supermount/inode.c:1.1 Mon Feb 26 17:55:16 1996
- +++ linux/fs/supermount/inode.c Sat Nov 9 17:27:25 1996
- @@ -0,0 +1,380 @@
- +/*
- + * linux/fs/supermount/inode.c
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + * from
- + *
- + * linux/fs/minix/inode.c
- + * Copyright (C) 1991, 1992 Linus Torvalds
- + *
- + * and
- + *
- + * linux/fs/ext2/inode.c
- + * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
- + * and 1993 Stephen Tweedie
- + */
- +
- +#include <asm/segment.h>
- +#include <asm/system.h>
- +
- +#include <linux/errno.h>
- +#include <linux/fs.h>
- +#include <linux/supermount_fs.h>
- +#include <linux/sched.h>
- +#include <linux/stat.h>
- +#include <linux/string.h>
- +#include <linux/locks.h>
- +#include <linux/mm.h>
- +
- +static void read_hidden_inode (struct inode *);
- +static void supermount_inode_open (struct inode *, int);
- +static void supermount_inode_write (struct inode *);
- +static void supermount_inode_release (struct inode *);
- +
- +/* Deal with the shadow interface. Whenever a subfs inode is
- + released, break the bi-directional link between them, and close and
- + iput the supermount inode. */
- +
- +struct inode_shadow_operations supermount_shadow_iops = {
- + supermount_inode_open,
- + supermount_inode_write,
- + supermount_inode_release,
- +};
- +
- +void supermount_inode_open (struct inode *inode, int flag)
- +{
- + if (flag & 2)
- + mark_subfs_dirty(inode->i_sb);
- +}
- +
- +void supermount_inode_write (struct inode *inode)
- +{
- + mark_subfs_dirty(inode->i_sb);
- +}
- +
- +void supermount_inode_release (struct inode *inode)
- +{
- + supermount_debug ("inode = %ld\n", inode->i_ino);
- + if (inode->u.supermount_i.i_hidden)
- + supermount_debug("subinode = %ld\n",
- + inode->u.supermount_i.i_hidden->i_ino);
- +
- + inode->u.supermount_i.i_hidden = NULL;
- + supermount_iclose(inode);
- +}
- +
- +
- +/* Do an iget on the appropriate subfs inode */
- +struct inode * subiget(struct inode * inode)
- +{
- + struct inode * tmp;
- + supermount_debug("subiget inode %ld\n", inode->i_ino);
- +
- + if (!S_ISDIR(inode->i_mode))
- + return 0;
- + if (supermount_media_check(inode->i_sb)) {
- + supermount_debug("media is invalid\n");
- + return 0;
- + }
- +
- + if (inode_is_obsolete(inode)) {
- + /* For obsolete directory with new mounted media ---
- + return the new root subinode. */
- + if (inode->u.supermount_i.i_hidden)
- + supermount_panic (inode->i_sb, "subiget",
- + "Hidden inode on obsolete inode %ld",
- + inode->i_ino);
- + tmp = inode->i_sb->u.supermount_sb.s_subfs->s_mounted;
- + inode->u.supermount_i.i_subino = tmp->i_ino;
- + tmp->i_count++;
- + supermount_debug("mapping obsolete inode %ld to "
- + "subroot inode %ld\n",
- + inode->i_ino, tmp->i_ino);
- + return tmp;
- + }
- +
- + if (inode->u.supermount_i.i_hidden) {
- + inode->u.supermount_i.i_hidden->i_count++;
- + supermount_debug("inode %ld/%ld, found hidden, "
- + "count now %d/%d\n",
- + inode->i_ino,
- + inode->u.supermount_i.i_hidden->i_ino,
- + inode->i_count,
- + inode->u.supermount_i.i_hidden->i_count);
- + return inode->u.supermount_i.i_hidden;
- + }
- + read_hidden_inode(inode);
- + if (!inode->u.supermount_i.i_hidden) {
- + supermount_debug("inode %ld, no subinode, count=%d\n",
- + inode->i_ino, inode->i_count);
- + return 0;
- + }
- +
- + supermount_debug("inode %ld/%ld, found new, "
- + "count now %d/%d\n",
- + inode->i_ino,
- + inode->u.supermount_i.i_hidden->i_ino,
- + inode->i_count,
- + inode->u.supermount_i.i_hidden->i_count);
- + return inode->u.supermount_i.i_hidden;
- +}
- +
- +/* We sometimes do a lookup on a subinode and want to get back a
- + superinode in return, with a single iget() outstanding on both (not
- + counting the i_shadow reference). supermount_attach generates the
- + superinode for a given subinode. */
- +struct inode * supermount_attach(struct super_block *sb, struct inode *inode)
- +{
- + struct inode *tmp;
- + unsigned long new_ino, incr=1237;
- +
- + supermount_debug ("inode = %ld\n", inode->i_ino);
- +
- + if (inode->i_shadow) {
- + supermount_debug ("return existing shadow %ld, count %d/%d\n",
- + inode->i_shadow->i_ino,
- + inode->i_shadow->i_count, inode->i_count);
- + inode->i_shadow->i_count++;
- + return inode->i_shadow;
- + }
- +
- + /* The rules are a little different at the root. */
- + if (inode == sb->u.supermount_sb.s_subfs->s_mounted) {
- + tmp = sb->s_mounted;
- + supermount_debug ("return existing superfs root %ld, "
- + "count %d/%d\n",
- + tmp->i_ino, tmp->i_count, inode->i_count);
- + tmp->i_count++;
- + return tmp;
- + }
- +
- + /* Find a new superinode, avoiding collisions with old
- + obsolete superinodes by a quadratic hash. */
- + new_ino = inode->i_ino;
- + for ( ; (tmp = iget(sb, new_ino)) && tmp->i_count > 1 &&
- + inode_is_obsolete(tmp); ) {
- + iput(tmp);
- + new_ino += incr;
- + new_ino &= 0xffffff;
- + incr <<= 1; incr++;
- + }
- +
- + tmp->u.supermount_i.i_subino = inode->i_ino;
- + /* If we found a previously obsolete inode which is now no
- + longer used, we can safely remove the obsolesence flag. */
- + if (inode_is_obsolete(tmp)) {
- + tmp->u.supermount_i.i_sb_version =
- + tmp->i_sb->u.supermount_sb.s_version;
- + }
- +
- + /* We have now done iget() on superi and subi. Doing the
- + attachment may incur another iget() on the subinode. */
- + if (!tmp->u.supermount_i.i_hidden) {
- + read_hidden_inode(tmp);
- + iput(inode);
- + }
- + return tmp;
- +}
- +
- +/* Supermount open/close inode. These functions maintain the
- + superblock reference counts of active inodes; the subfs is
- + suspended when that count reaches zero.
- +
- + Files are opened on any significant reference, and are not closed
- + until they become fully dereferenced (during the last iput).
- + Directories, on the other hand, are always closed unless they are
- + active and opened; a directory referenced as CWD is not open.
- +
- + The difference is in the way the application gets given inodes.
- + For dirs and symlinks, it will be given the superinode to deal
- + with; for other file types, we return the subinode. */
- +
- +
- +void supermount_iopen(struct inode * inode)
- +{
- + supermount_debug ("inode %ld, count %d\n",
- + inode->i_ino, inode->i_count);
- + if (inode->i_sb->u.supermount_sb.s_state == SUPERMOUNT_UNMOUNTED)
- + supermount_panic (inode->i_sb, "supermount_iopen",
- + "opening inode on unmounted subfs");
- + if (!inode->u.supermount_i.i_counted) {
- + supermount_debug("Opened inode %ld\n", inode->i_ino);
- + inode->u.supermount_i.i_counted = 1;
- + if (!subfs_is_active(inode->i_sb)) {
- + supermount_debug ("going online.\n");
- + inode->i_sb->u.supermount_sb.s_state =
- + SUPERMOUNT_ONLINE;
- + }
- + inode->i_sb->u.supermount_sb.s_opencount++;
- + }
- +}
- +
- +void supermount_iclose(struct inode * inode)
- +{
- + supermount_debug ("inode %ld, count %d\n",
- + inode->i_ino, inode->i_count);
- + if (inode->u.supermount_i.i_counted) {
- + supermount_debug("Closed inode %ld\n", inode->i_ino);
- + inode->u.supermount_i.i_counted = 0;
- + inode->i_sb->u.supermount_sb.s_opencount--;
- + if (!subfs_is_active(inode->i_sb))
- + supermount_go_inactive(inode->i_sb);
- + }
- +}
- +
- +void supermount_go_inactive(struct super_block *sb)
- +{
- + supermount_debug("Checking state\n");
- + if (!subfs_is_active(sb)) {
- + supermount_debug("going offline.\n");
- + sb->u.supermount_sb.s_state =
- + SUPERMOUNT_SUSPENDED;
- + if (subfs_is_dirty(sb)) {
- + mark_subfs_clean(sb);
- + fsync_dev(sb->u.supermount_sb.s_subfs->s_dev);
- + }
- + }
- +}
- +
- +static void read_hidden_inode (struct inode * inode)
- +{
- + struct super_block * sb;
- + struct inode * tmp;
- +
- + supermount_debug("inode = %ld\n", inode->i_ino);
- + supermount_media_check(inode->i_sb);
- +
- + if (inode->i_sb->u.supermount_sb.s_state ==
- + SUPERMOUNT_UNMOUNTED) {
- + supermount_panic (inode->i_sb, "read_hidden_inode",
- + "Trying to read inode on unmounted media");
- + }
- + sb=inode->i_sb->u.supermount_sb.s_subfs;
- + /* The root inode is a bit special. For that one, the
- + subinode is the root of the subfs, and we can't guarantee
- + its inode number in advance. */
- + if (inode->i_ino == SUPERMOUNT_ROOT_INO) {
- + tmp = sb->s_mounted;
- + tmp->i_count++;
- + } else {
- + if (!inode->u.supermount_i.i_subino)
- + inode->u.supermount_i.i_subino = inode->i_ino;
- + tmp = iget(sb, inode->u.supermount_i.i_subino);
- + }
- + if (!tmp)
- + return;
- +
- + /* If the inode is already linked to its superinode, don't do
- + any further processing. Also, don't bother trying to
- + attach to the superinode if we are reading from an obsolete
- + superinode. */
- + if (tmp->i_shadow || inode_is_obsolete(inode))
- + return;
- + tmp->i_shadow = inode;
- + inode->u.supermount_i.i_hidden = tmp;
- + inode->i_count++;
- + supermount_iopen(inode);
- +
- + inode->i_mode = tmp->i_mode;
- + inode->i_uid = tmp->i_uid;
- + inode->i_gid = tmp->i_gid;
- + inode->i_nlink = tmp->i_nlink;
- + inode->i_size = tmp->i_size;
- + inode->i_atime = tmp->i_atime;
- + inode->i_ctime = tmp->i_ctime;
- + inode->i_mtime = tmp->i_mtime;
- + inode->i_blksize = tmp->i_blksize;
- + inode->i_blocks = tmp->i_blocks;
- + inode->i_rdev = tmp->i_rdev;
- + inode->i_version = ++event;
- +
- + if (S_ISDIR(inode->i_mode))
- + inode->i_op = &supermount_dir_iops;
- + else
- + inode->i_op = NULL;
- +}
- +
- +void supermount_read_inode (struct inode * inode)
- +{
- + supermount_debug ("inode = %ld\n", inode->i_ino);
- +
- + inode->i_shadow_op = &supermount_shadow_iops;
- + inode->u.supermount_i.i_sb_version =
- + inode->i_sb->u.supermount_sb.s_version;
- +
- + switch (inode->i_ino) {
- + case SUPERMOUNT_ROOT_INO:
- + if (inode->i_sb->u.supermount_sb.s_state !=
- + SUPERMOUNT_UNMOUNTED) {
- + supermount_panic (inode->i_sb, "supermount_read_inode",
- + "Help - trying to read root while "
- + "already mounted!");
- + }
- + /* Fall through */
- + case SUPERMOUNT_HIDDEN_INO:
- + inode->i_mode = inode->i_sb->u.supermount_sb.s_default_mode;
- + inode->i_uid = 0;
- + inode->i_gid = 0;
- + inode->i_nlink = 1;
- + inode->i_size = 0;
- + inode->i_atime = CURRENT_TIME;
- + inode->i_ctime = CURRENT_TIME;
- + inode->i_mtime = CURRENT_TIME;
- + inode->i_blksize = inode->i_sb->s_blocksize;
- + inode->i_blocks = 0;
- + inode->i_version = ++event;
- + inode->i_op = (inode->i_ino == SUPERMOUNT_ROOT_INO)
- + ? &supermount_dir_iops : NULL;
- + return;
- + default:
- + ;
- + }
- +}
- +
- +void supermount_write_inode (struct inode * inode)
- +{
- + struct super_block *tmp;
- + tmp = inode->i_sb->u.supermount_sb.s_subfs;
- +
- + if (inode->u.supermount_i.i_hidden &&
- + tmp && tmp->s_op && tmp->s_op->write_inode)
- + tmp->s_op->write_inode(inode->u.supermount_i.i_hidden);
- +
- + mark_subfs_dirty(inode->i_sb);
- +}
- +
- +int supermount_permission (struct inode * inode, int mask)
- +{
- + unsigned short mode;
- + struct inode *subi;
- +
- + supermount_debug("inode %ld, mask 0%o\n", inode->i_ino, mask);
- +
- + subi = subiget(inode);
- + if (!subi)
- + return -EIO;
- + if (subi->i_op && subi->i_op->permission) {
- + int rc = subi->i_op->permission(subi, mask);
- + iput(subi);
- + return rc;
- + }
- +
- + mode = inode->i_mode;
- + /*
- + * Special case, access is always granted for root
- + */
- + if (fsuser()) {
- + iput(subi);
- + return 0;
- + } else if (current->fsuid == inode->i_uid)
- + mode >>= 6;
- + else if (in_group_p (inode->i_gid))
- + mode >>= 3;
- + iput(subi);
- + if (((mode & mask & S_IRWXO) == mask))
- + return 0;
- + else
- + return -EACCES;
- +}
- Index: linux/fs/supermount/namei.c
- diff -u linux/fs/supermount/namei.c:1.1 linux/fs/supermount/namei.c:1.1.6.1
- --- linux/fs/supermount/namei.c:1.1 Mon Feb 26 17:55:16 1996
- +++ linux/fs/supermount/namei.c Sat Nov 9 17:27:25 1996
- @@ -0,0 +1,348 @@
- +/*
- + * linux/fs/supermount/namei.c
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + * from
- + *
- + * linux/fs/minix/namei.c
- + * Copyright (C) 1991, 1992 Linus Torvalds
- + *
- + * and
- + *
- + * linux/fs/ext2/namei.c
- + * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
- + */
- +
- +/* This file handles almost all of the normal filesystem running of
- + supermount. We don't have to deal to much with the subfs
- + interface, since we just pass subinodes out to the application on
- + demand. */
- +
- +#include <asm/segment.h>
- +#include <linux/errno.h>
- +#include <linux/fs.h>
- +#include <linux/supermount_fs.h>
- +#include <linux/fcntl.h>
- +#include <linux/sched.h>
- +#include <linux/stat.h>
- +#include <linux/string.h>
- +#include <linux/locks.h>
- +
- +/* Attach a superinode to a subinode, and prepare a result for the
- + upper VFS layers. We return the superinode for directories, and
- + the subinode for other file types.
- + */
- +static void attach_and_prepare(struct super_block *sb,
- + struct inode *subi, struct inode **result)
- +{
- + struct inode *superi;
- + superi = supermount_attach(sb, subi);
- + /* We have now done iget() on superi and subi. */
- +
- + /* If the subfs inode is a directory or a symlink, then we
- + need to deal with it ourselves, and only give back the
- + superinode to the application. Otherwise, we can just
- + return the subfs inode. */
- + if (S_ISDIR(subi->i_mode)) {
- + superi->i_op = &supermount_dir_iops;
- + iput(subi);
- + *result = superi;
- + return;
- + } else {
- + /* Not a directory-related inode, so we return the
- + subfs inode to the upper layers. We still need the
- + supermount inode in that case, though, to maintain
- + reference counts in the supermount superblock. */
- +
- + iput(superi);
- + *result = subi;
- + return;
- + }
- +}
- +
- +int supermount_lookup (struct inode * dir, const char * name, int len,
- + struct inode ** result)
- +{
- + struct inode *subi, *subdir;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s\n",
- + dir->i_ino, len, name);
- +
- + *result = NULL;
- + if (!dir)
- + return -ENOENT;
- + if (!S_ISDIR(dir->i_mode)) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!(subdir = subiget(dir))) {
- + /* This now becomes the *easy* case. :-) */
- + iput (dir);
- + return -EIO;
- + }
- +
- + rc = subdir->i_op->lookup(subdir, name, len, &subi);
- + supermount_go_inactive(dir->i_sb);
- + iput (dir);
- + if (rc)
- + return rc;
- + /* It worked, so now create a shadow supermount inode for the
- + result... */
- + attach_and_prepare(dir->i_sb, subi, result);
- + return 0;
- +}
- +
- +int supermount_create (struct inode * dir,const char * name, int len, int mode,
- + struct inode ** result)
- +{
- + struct inode * inode, * subi;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s, mode = %o\n",
- + dir->i_ino, len, name, mode);
- +
- + *result = NULL;
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->create) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->create(inode, name, len, mode, &subi);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + if (rc)
- + return rc;
- + attach_and_prepare(dir->i_sb, subi, result);
- + return 0;
- +}
- +
- +int supermount_mknod (struct inode * dir, const char * name, int len, int mode,
- + int rdev)
- +{
- + struct inode * inode;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s, mode = %o\n",
- + dir->i_ino, len, name, mode);
- +
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->mknod) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->mknod(inode, name, len, mode, rdev);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + return rc;
- +}
- +
- +int supermount_mkdir (struct inode * dir, const char * name, int len, int mode)
- +{
- + struct inode * inode;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s, mode = %o\n",
- + dir->i_ino, len, name, mode);
- +
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->mkdir) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->mkdir(inode, name, len, mode);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + return rc;
- +}
- +
- +int supermount_rmdir (struct inode * dir, const char * name, int len)
- +{
- + struct inode * inode;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s\n",
- + dir->i_ino, len, name);
- +
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->rmdir) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->rmdir(inode, name, len);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + return rc;
- +}
- +
- +int supermount_unlink (struct inode * dir, const char * name, int len)
- +{
- + struct inode * inode;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s\n",
- + dir->i_ino, len, name);
- +
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->unlink) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->unlink(inode, name, len);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + return rc;
- +}
- +
- +int supermount_symlink (struct inode * dir, const char * name, int len,
- + const char * symname)
- +{
- + struct inode * inode;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s, link = %s\n",
- + dir->i_ino, len, name, symname);
- +
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->symlink) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->symlink(inode, name, len, symname);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + return rc;
- +}
- +
- +/* This probably won't work because higher levels will complain about
- + cross-device links. */
- +int supermount_link (struct inode * oldinode, struct inode * dir,
- + const char * name, int len)
- +{
- + struct inode * inode;
- + int rc;
- +
- + supermount_debug ("inode = %ld, name = %*s, link to inode %ld\n",
- + dir->i_ino, len, name, oldinode->i_ino);
- +
- + if (!dir)
- + return -ENOENT;
- + inode = subiget(dir);
- + if (!inode) {
- + iput(dir);
- + return -ENOENT;
- + }
- + if (!inode->i_op || !inode->i_op->link) {
- + iput(dir);
- + iput(inode);
- + return -EPERM;
- + }
- +
- + rc = inode->i_op->link(oldinode, inode, name, len);
- + mark_subfs_dirty(dir->i_sb);
- + supermount_go_inactive(dir->i_sb);
- + iput(dir);
- + return rc;
- +}
- +
- +int supermount_rename (struct inode * old_dir, const char * old_name,
- + int old_len,
- + struct inode * new_dir, const char * new_name,
- + int new_len, int must_be_dir)
- +{
- + struct inode * old_subi, * new_subi;
- + int rc;
- +
- + supermount_debug ("from inode %ld, %*s to inode %ld, %*s\n",
- + old_dir->i_ino, old_len, old_name,
- + new_dir->i_ino, new_len, new_name);
- +
- + if (!old_dir || !new_dir)
- + return -ENOENT;
- + old_subi = subiget(old_dir);
- + if (!old_subi) {
- + iput(old_dir);
- + iput(new_dir);
- + return -ENOENT;
- + }
- + new_subi = subiget(new_dir);
- + if (!new_subi) {
- + iput(old_dir);
- + iput(new_dir);
- + iput(old_subi);
- + return -ENOENT;
- + }
- +
- + if (!old_subi->i_op || !old_subi->i_op->rename) {
- + iput(old_dir);
- + iput(new_dir);
- + iput(old_subi);
- + iput(new_subi);
- + return -EPERM;
- + }
- +
- + rc = old_subi->i_op->rename(old_subi, old_name, old_len,
- + new_subi, new_name, new_len,
- + must_be_dir);
- + mark_subfs_dirty(old_dir->i_sb);
- + supermount_go_inactive(old_dir->i_sb);
- + iput(old_dir);
- + iput(new_dir);
- + return rc;
- +}
- Index: linux/fs/supermount/super.c
- diff -u linux/fs/supermount/super.c:1.1 linux/fs/supermount/super.c:1.1.6.2
- --- linux/fs/supermount/super.c:1.1 Mon Feb 26 17:55:16 1996
- +++ linux/fs/supermount/super.c Sat Nov 9 19:57:42 1996
- @@ -0,0 +1,431 @@
- +/*
- + * linux/fs/supermount/super.c
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + * from
- + *
- + * linux/fs/minix/inode.c
- + * Copyright (C) 1991, 1992 Linus Torvalds
- + *
- + * and
- + *
- + * linux/fs/ext2/super.c
- + * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
- + */
- +
- +#include <stdarg.h>
- +
- +#include <asm/segment.h>
- +#include <asm/system.h>
- +
- +#include <linux/errno.h>
- +#include <linux/fs.h>
- +#include <linux/supermount_fs.h>
- +#include <linux/malloc.h>
- +#include <linux/sched.h>
- +#include <linux/stat.h>
- +#include <linux/string.h>
- +#include <linux/locks.h>
- +#include <linux/major.h>
- +
- +/* From fs/super.c */
- +extern int do_umount(kdev_t);
- +
- +#ifdef SUPERMOUNT_DEBUG
- +char supermount_debug_enable = 0;
- +#endif
- +
- +static struct super_operations supermount_sops = {
- + supermount_read_inode,
- + NULL,
- + supermount_write_inode,
- + NULL, /* put_inode */
- + supermount_put_super,
- + supermount_write_super,
- + supermount_statfs,
- + NULL, /* supermount_remount */
- +};
- +
- +static char error_buf[1024];
- +
- +/* Mount and mount the hidden fs */
- +static void umount_subfs(struct super_block *);
- +
- +void supermount_error (struct super_block * sb, const char * function,
- + const char * fmt, ...)
- +{
- + va_list args;
- +
- + va_start (args, fmt);
- + vsprintf (error_buf, fmt, args);
- + va_end (args);
- + printk (KERN_CRIT "SUPERMOUNT error (device %d/%d): %s: %s\n",
- + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
- + /* @@ Do we want to do any special error handling here? */
- +}
- +
- +NORET_TYPE void supermount_panic (struct super_block * sb,
- + const char * function,
- + const char * fmt, ...)
- +{
- + va_list args;
- +
- + va_start (args, fmt);
- + vsprintf (error_buf, fmt, args);
- + va_end (args);
- + panic ("SUPERMOUNT panic (device %d/%d): %s: %s\n",
- + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
- +}
- +
- +void supermount_warning (struct super_block * sb, const char * function,
- + const char * fmt, ...)
- +{
- + va_list args;
- +
- + va_start (args, fmt);
- + vsprintf (error_buf, fmt, args);
- + va_end (args);
- + printk (KERN_WARNING "SUPERMOUNT-fs warning (device %d/%d): %s: %s\n",
- + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
- +}
- +
- +/* Release the superblock and any resources it has reserved */
- +void supermount_put_super (struct super_block * sb)
- +{
- + lock_super (sb);
- + if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED)
- + umount_subfs (sb);
- + sb->s_dev = 0;
- + unlock_super (sb);
- +}
- +
- +
- +static int copy_option(const char **option, const char *val)
- +{
- + char *tmp;
- + supermount_debug ("assigning value \"%s\"\n", val);
- + if (!val || !*val)
- + return -EINVAL;
- + tmp = (char *) kmalloc(1 + strlen(val), GFP_KERNEL);
- + if (!tmp)
- + return -ENOMEM;
- + strcpy(tmp, val);
- + *option = tmp;
- + return 0;
- +}
- +
- +/*
- + * This function has been shamelessly adapted from the msdos fs
- + */
- +static int parse_options (char * options, struct super_block *sb)
- +{
- + char * this_char;
- + char * value;
- + int rc;
- +
- + if (!options)
- + return 0;
- + while ((this_char = options)) {
- + if (!strncmp(this_char, "--,", 3))
- + this_char += 2;
- + if (*this_char == ',') {
- + /* An empty option, or the option "--",
- + introduces options to be passed through to
- + the subfs */
- + supermount_debug ("assigning remainder\n");
- + return copy_option(&sb->u.supermount_sb.s_data,
- + ++this_char);
- + }
- + if ((options = strchr (this_char, ',')))
- + *options++ = 0;
- +
- + if ((value = strchr (this_char, '=')) != NULL)
- + *value++ = 0;
- +
- + supermount_debug ("parsing option \"%s\"\n", this_char);
- + if (!strcmp (this_char, "fs")) {
- + rc = copy_option(&sb->u.supermount_sb.s_type, value);
- + if (rc) return rc;
- + } else if (!strcmp (this_char, "dev")) {
- + rc = copy_option(&sb->u.supermount_sb.s_devname,
- + value);
- + if (rc) return rc;
- + } else if (!strcmp (this_char, "debug")) {
- + supermount_debug_enable = 1;
- + } else {
- + printk ("supermount: "
- + "Unrecognized mount option %s\n", this_char);
- + return -EINVAL;
- + }
- + }
- + return 0;
- +}
- +
- +/* read_super: the main mount() entry point into the VFS layer. */
- +struct super_block * supermount_read_super (struct super_block * sb,
- + void * data,
- + int silent)
- +{
- + sb->s_blocksize = 1024;
- + sb->s_blocksize_bits = 10;
- + sb->s_magic = SUPERMOUNT_SUPER_MAGIC;
- + sb->s_op = &supermount_sops;
- + unlock_super(sb);
- + sb->u.supermount_sb.s_state = SUPERMOUNT_UNMOUNTED;
- + sb->u.supermount_sb.s_default_mode = 0777 | S_IFDIR;
- + sb->u.supermount_sb.s_mflags = sb->s_flags & (MS_REMOUNT - 1);
- + sb->u.supermount_sb.s_data = NULL;
- + sb->u.supermount_sb.s_undermount = NULL;
- + sb->u.supermount_sb.s_subfs = NULL;
- + sb->u.supermount_sb.s_opencount = 0;
- + sb->u.supermount_sb.s_dirty = 0;
- + sb->u.supermount_sb.s_type = NULL;
- + sb->u.supermount_sb.s_devname = NULL;
- +
- + if (parse_options ((char *) data, sb)) {
- + sb->s_dev = 0;
- + return NULL;
- + }
- + if (!sb->u.supermount_sb.s_type)
- + copy_option(&sb->u.supermount_sb.s_type, "msdos");
- + if (!sb->u.supermount_sb.s_devname)
- + copy_option(&sb->u.supermount_sb.s_devname, "/dev/fd0");
- +
- + sb->s_flags = sb->u.supermount_sb.s_mflags;
- + if (!(sb->s_mounted = iget(sb, SUPERMOUNT_ROOT_INO))) {
- + sb->s_dev = 0;
- + supermount_error (sb, "supermount_read_super",
- + "get root inode failed\n");
- + return NULL;
- + }
- + return sb;
- +}
- +
- +void supermount_write_super (struct super_block * sb)
- +{
- + supermount_media_check(sb);
- + if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
- + struct super_block *tmp = sb->u.supermount_sb.s_subfs;
- + if (tmp && tmp->s_op && tmp->s_op->write_super)
- + tmp->s_op->write_super(tmp);
- + }
- + sb->s_dirt = 0;
- +}
- +
- +#if 0
- +int supermount_remount (struct super_block * sb, int * flags, char * data)
- +{
- +}
- +#endif /* 0 */
- +
- +void supermount_statfs (struct super_block * sb, struct statfs * buf,
- + int bufsize)
- +{
- + unsigned short fs;
- + struct statfs tmp;
- + supermount_media_check(sb);
- +
- + if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
- + struct super_block * tmpsb =
- + sb->u.supermount_sb.s_undermount->i_mount->i_sb;
- + fs = get_fs();
- + set_fs(KERNEL_DS);
- + if (tmpsb->s_op && tmpsb->s_op->statfs)
- + tmpsb->s_op->statfs(tmpsb, &tmp, sizeof(tmp));
- + set_fs(fs);
- + } else {
- + tmp.f_bsize = sb->s_blocksize;
- + tmp.f_blocks = 0;
- + tmp.f_bfree = 0;
- + tmp.f_bavail = 0;
- + tmp.f_files = 0;
- + tmp.f_ffree = 0;
- + tmp.f_namelen = 0;
- + }
- + tmp.f_type = SUPERMOUNT_SUPER_MAGIC;
- + memcpy_tofs(buf, &tmp, bufsize);
- +}
- +
- +/* Check for media change, but without invalidating buffers and inodes */
- +static int just_check_disk_change(dev_t dev)
- +{
- + if (!query_disk_change(dev))
- + return 0;
- + supermount_debug("Disk change detected on device %d/%d\n",
- + MAJOR(dev), MINOR(dev));
- + return 1;
- +}
- +
- +static void umount_subfs(struct super_block *sb)
- +{
- + int retval;
- + struct inode *inode, *subi;
- +
- + supermount_debug("Trying to unmount device %s.\n",
- + sb->u.supermount_sb.s_devname);
- +
- + /* Detach the subfs from the supermount root inode */
- + inode = sb->s_mounted;
- + /* Inode may not be set if we are currently unmounting the superfs */
- + if (inode) {
- + subi = inode->u.supermount_i.i_hidden;
- + if (subi) {
- + subi->i_shadow = 0;
- + inode->u.supermount_i.i_hidden = 0;
- + iput(inode);
- + }
- + }
- +
- + if (sb->u.supermount_sb.s_subfs->s_mounted->i_count != 1)
- + supermount_panic (sb, "umount_subfs",
- + "subfs root i_count = %d, should be 1\n",
- + sb->u.supermount_sb.s_subfs->s_mounted->i_count);
- + if (sb->u.supermount_sb.s_undermount->i_count != 1)
- + supermount_panic (sb, "umount_subfs",
- + "undermount i_count = %d, should be 1\n",
- + sb->u.supermount_sb.s_subfs->s_mounted->i_count);
- +
- + sb->u.supermount_sb.s_subfs->s_mounted->i_count++;
- + sb->u.supermount_sb.s_state = SUPERMOUNT_UNMOUNTED;
- + retval = do_umounti(sb->u.supermount_sb.s_subfs->s_mounted);
- + if (retval)
- + supermount_panic (sb, "umount_subfs",
- + "Help - can't umount subfs!!!");
- + supermount_debug("subfs is unmounted.\n");
- + sb->u.supermount_sb.s_undermount = 0;
- + sb->u.supermount_sb.s_version = ++event;
- + sb->u.supermount_sb.s_subfs = 0;
- + sb->s_flags = sb->u.supermount_sb.s_mflags;
- + if (inode)
- + inode->i_mode = sb->u.supermount_sb.s_default_mode;
- +}
- +
- +/* Return 0 (OK) if medium is valid. */
- +int supermount_media_check(struct super_block * sb)
- +{
- + int retval;
- + unsigned short fs;
- +
- + /* If there are still files open, we never bother checking the
- + medium. */
- + if (sb->u.supermount_sb.s_subfs &&
- + subfs_is_active(sb)) {
- + supermount_debug ("subfs is active.\n");
- + return 0;
- + }
- +
- + supermount_debug ("starting (%sactive now)\n",
- + (sb->u.supermount_sb.s_subfs &&
- + subfs_is_active(sb)) ?
- + "" : "not ");
- +
- + lock_super(sb);
- +
- + /* Are we checking for mount or unmount/remount? */
- + if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
- + /* Already mounted --- check for disk change or
- + disk not present */
- + int dev = sb->u.supermount_sb.s_subfs->s_dev;
- + if (!just_check_disk_change(dev)) {
- + unlock_super(sb);
- + return 0;
- + }
- +
- + /* We have a disk change! Unmount the subfs */
- + supermount_debug ("trying to unmount\n");
- + umount_subfs(sb);
- + /* The call to just_check_disk_change may clear the media-
- + changed flag on the device, so we need to force a media
- + invalidation. We don't want to do this before unmounting
- + the subfs, naturally! */
- + invalidate_media(dev);
- + /* Now we are unmounted; fall through to the next check. */
- + }
- +
- + if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
- + unlock_super(sb);
- + return 0;
- + }
- +
- + /* OK, we're unmounted now --- can we remount? Please? */
- + if (!sb->u.supermount_sb.s_undermount) {
- + sb->u.supermount_sb.s_undermount =
- + iget(sb, SUPERMOUNT_HIDDEN_INO);
- + if (!sb->u.supermount_sb.s_undermount)
- + supermount_panic (sb, "supermount_media_check",
- + "Can't get root hidden inode!");
- + sb->u.supermount_sb.s_undermount->i_flags |= S_UNBOUND;
- + }
- +
- + sb->u.supermount_sb.s_version = ++event;
- + sb->s_mounted->u.supermount_i.i_sb_version = event;
- + supermount_debug ("trying to mount\n");
- + supermount_debug ("fs=%s, dev=%s, data=%s, flags=%08lx\n",
- + sb->u.supermount_sb.s_type,
- + sb->u.supermount_sb.s_devname,
- + sb->u.supermount_sb.s_data,
- + sb->s_flags);
- + fs = get_fs();
- + set_fs(KERNEL_DS);
- + sb->s_flags = sb->u.supermount_sb.s_mflags,
- + retval = do_mounti(sb->u.supermount_sb.s_undermount,
- + "<supermount>",
- + sb->u.supermount_sb.s_devname,
- + sb->u.supermount_sb.s_type,
- + sb->s_flags | MS_MGC_VAL,
- + sb->u.supermount_sb.s_data);
- + if (retval == -EROFS && !(sb->u.supermount_sb.s_mflags & MS_RDONLY)) {
- + /* OK, that failed, so try it readonly */
- + sb->s_flags |= MS_RDONLY;
- + retval = do_mounti(sb->u.supermount_sb.s_undermount,
- + "<supermount>",
- + sb->u.supermount_sb.s_devname,
- + sb->u.supermount_sb.s_type,
- + sb->s_flags | MS_MGC_VAL,
- + sb->u.supermount_sb.s_data);
- + }
- + set_fs(fs);
- +
- + unlock_super(sb);
- + if (retval) {
- + sb->s_flags = sb->u.supermount_sb.s_mflags;
- + iput(sb->u.supermount_sb.s_undermount);
- + sb->u.supermount_sb.s_undermount = 0;
- + supermount_debug ("Mount failed, errno %d\n", -retval);
- + return 1;
- + }
- + /* Hey --- success!!! */
- + sb->u.supermount_sb.s_subfs = sb->u.supermount_sb.s_undermount
- + ->i_mount->i_sb;
- + if (!sb->u.supermount_sb.s_subfs->s_mounted)
- + supermount_panic (sb, "supermount_media_check",
- + "Mounted subfs has no root inode!");
- + sb->u.supermount_sb.s_state = SUPERMOUNT_SUSPENDED;
- + supermount_debug ("Mount succeeded!\n");
- + /* For counting open inodes on the subfs, we rely on the fact
- + that the root inode is always exactly one count. So make
- + sure we guarantee it is always open! */
- + supermount_iopen(sb->s_mounted);
- + sb->s_mounted->i_flags |= S_UNBOUND;
- + return 0;
- +}
- +
- +/* Check whether an inode still belongs to valid medium. */
- +int supermount_check_inode(struct inode * inode)
- +{
- + supermount_debug ("inode = %ld\n", inode->i_ino);
- +
- + if (supermount_media_check(inode->i_sb))
- + return 1;
- + if (inode_is_obsolete(inode)) {
- + /* What happens if we remount an old disk, and get
- + back the same superinode number? subiget() will
- + handle it through the i_subino field, and
- + supermount_attach will avoid reusing the old
- + inode. */
- + return 1;
- + }
- + return 0;
- +}
- Index: linux/include/linux/fs.h
- diff -u linux/include/linux/fs.h:1.12 linux/include/linux/fs.h:1.12.2.1
- --- linux/include/linux/fs.h:1.12 Wed Nov 6 23:17:37 1996
- +++ linux/include/linux/fs.h Sat Nov 9 17:26:30 1996
- @@ -74,6 +74,10 @@
- #define S_WRITE 128 /* Write on file/directory/symlink */
- #define S_APPEND 256 /* Append-only file */
- #define S_IMMUTABLE 512 /* Immutable file */
- +#define S_UNBOUND 1024 /* inode is not bound to user space,
- + and so the filesystem may be
- + unmounted even if this inode is in
- + use. */
-
- /*
- * Flags that can be altered by MS_REMOUNT
- @@ -103,6 +107,7 @@
- #define IS_WRITABLE(inode) ((inode)->i_flags & S_WRITE)
- #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
- #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
- +#define IS_UNBOUND(inode) ((inode)->i_flags & S_UNBOUND)
-
- /* the read-only stuff doesn't really belong here, but any other place is
- probably as bad and I don't want to create yet another include file. */
- @@ -216,6 +221,7 @@
- }
-
- #include <linux/pipe_fs_i.h>
- +#include <linux/supermount_fs_i.h>
- #include <linux/minix_fs_i.h>
- #include <linux/ext_fs_i.h>
- #include <linux/ext2_fs_i.h>
- @@ -284,6 +290,8 @@
- unsigned long i_nrpages;
- struct semaphore i_sem;
- struct inode_operations *i_op;
- + struct inode * i_shadow;
- + struct inode_shadow_operations * i_shadow_op;
- struct super_block *i_sb;
- struct wait_queue *i_wait;
- struct file_lock *i_flock;
- @@ -305,6 +313,7 @@
- unsigned short i_writecount;
- union {
- struct pipe_inode_info pipe_i;
- + struct supermount_inode_info supermount_i;
- struct minix_inode_info minix_i;
- struct ext_inode_info ext_i;
- struct ext2_inode_info ext2_i;
- @@ -402,6 +411,7 @@
-
- extern int fasync_helper(struct inode *, struct file *, int, struct fasync_struct **);
-
- +#include <linux/supermount_fs_sb.h>
- #include <linux/minix_fs_sb.h>
- #include <linux/ext_fs_sb.h>
- #include <linux/ext2_fs_sb.h>
- @@ -431,6 +441,7 @@
- struct inode * s_mounted;
- struct wait_queue * s_wait;
- union {
- + struct supermount_sb_info supermount_sb;
- struct minix_sb_info minix_sb;
- struct ext_sb_info ext_sb;
- struct ext2_sb_info ext2_sb;
- @@ -491,6 +502,12 @@
- int (*smap) (struct inode *,int);
- };
-
- +struct inode_shadow_operations {
- + void (*open) (struct inode *, int);
- + void (*write) (struct inode *);
- + void (*release) (struct inode *);
- +};
- +
- struct super_operations {
- void (*read_inode) (struct inode *);
- int (*notify_change) (struct inode *, struct iattr *);
- @@ -600,9 +617,11 @@
- }
-
- extern int check_disk_change(kdev_t dev);
- +extern int query_disk_change(kdev_t dev);
- extern void invalidate_inodes(kdev_t dev);
- extern void invalidate_inode_pages(struct inode *);
- extern void invalidate_buffers(kdev_t dev);
- +extern void invalidate_media(kdev_t dev);
- extern int floppy_is_wp(int minor);
- extern void sync_inodes(kdev_t dev);
- extern void sync_dev(kdev_t dev);
- @@ -663,6 +682,9 @@
-
- extern void show_buffers(void);
- extern void mount_root(void);
- +extern int do_mounti(struct inode *_inode, const char *, const char *,
- + const char *, unsigned long, const void *);
- +extern int do_umounti(struct inode *);
-
- #ifdef CONFIG_BLK_DEV_INITRD
- extern kdev_t real_root_dev;
- Index: linux/include/linux/supermount_fs.h
- diff -u linux/include/linux/supermount_fs.h:1.1 linux/include/linux/supermount_fs.h:1.1.4.1
- --- linux/include/linux/supermount_fs.h:1.1 Mon Feb 26 17:55:21 1996
- +++ linux/include/linux/supermount_fs.h Sat Nov 9 17:27:49 1996
- @@ -0,0 +1,165 @@
- +/*
- + * linux/include/linux/supermount_fs.h
- + *
- + * Defines and strutures for the dynamic remounting of removable media
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + * from
- + *
- + * linux/include/linux/minix_fs.h
- + * Copyright (C) 1991, 1992 Linus Torvalds
- + *
- + * and
- + *
- + * linux/include/linux/ext2_fs.h
- + * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
- + */
- +
- +#ifndef _LINUX_SUPERMOUNT_FS_H
- +#define _LINUX_SUPERMOUNT_FS_H
- +
- +#include <linux/types.h>
- +
- +#define SUPERMOUNT_DEBUG
- +
- +#define SUPERMOUNT_VERSION "0.4"
- +
- +/*
- + * Debug code
- + */
- +#ifdef SUPERMOUNT_DEBUG
- + extern char supermount_debug_enable;
- +
- + #define supermount_debug(f, a...) \
- + { \
- + if (supermount_debug_enable) { \
- + printk ("SUPERMOUNT DEBUG (%s, %d): %s: ", \
- + __FILE__, __LINE__, __FUNCTION__); \
- + printk (f, ## a); \
- + } \
- + }
- +#else
- + #define supermount_debug(f, a...) /**/
- +#endif
- +
- +/*
- + * Special inodes numbers
- + */
- +#define SUPERMOUNT_HIDDEN_INO 0 /* Hidden inode for
- + sub-mounting */
- +#define SUPERMOUNT_ROOT_INO 1 /* Root inode */
- +
- +/*
- + * The supermount superblock magic number
- + */
- +#define SUPERMOUNT_SUPER_MAGIC 0x9fa1
- +
- +#ifdef __KERNEL__
- +/*
- + * Function prototypes
- + */
- +
- +/*
- + * Ok, these declarations are also in <linux/kernel.h> but none of the
- + * supermount source programs needs to include it so they are duplicated here.
- + */
- +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
- +# define NORET_TYPE __volatile__
- +# define ATTRIB_NORET /**/
- +# define NORET_AND /**/
- +#else
- +# define NORET_TYPE /**/
- +# define ATTRIB_NORET __attribute__((noreturn))
- +# define NORET_AND noreturn,
- +#endif
- +
- +/* How to test if a supermount filesystem is active or not: */
- +static inline int subfs_is_active(struct super_block *sb)
- +{
- + /* The subfs is deemed inactive iff only the root is open, and
- + the its i_count is one. */
- + return (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED &&
- + (sb->u.supermount_sb.s_opencount > 1 ||
- + sb->u.supermount_sb.s_undermount->i_mount->i_count > 1));
- +}
- +
- +/* How to test if an inode is obsolete: */
- +static inline int inode_is_obsolete(struct inode *inode)
- +{
- + return (inode->u.supermount_i.i_sb_version !=
- + inode->i_sb->u.supermount_sb.s_version);
- +}
- +
- +/* Manage the subfs dirty flag */
- +static inline void mark_subfs_dirty(struct super_block *sb)
- +{
- + sb->u.supermount_sb.s_dirty = 1;
- +}
- +static inline void mark_subfs_clean(struct super_block *sb)
- +{
- + sb->u.supermount_sb.s_dirty = 0;
- +}
- +static inline int subfs_is_dirty(struct super_block *sb)
- +{
- + return (sb->u.supermount_sb.s_dirty);
- +}
- +
- +/* inode.c */
- +extern struct inode * subiget(struct inode *);
- +extern void supermount_iopen(struct inode *);
- +extern void supermount_iclose(struct inode *);
- +extern void supermount_go_inactive(struct super_block *);
- +extern struct inode * supermount_attach(struct super_block *, struct inode *);
- +extern void supermount_read_inode (struct inode *);
- +extern void supermount_write_inode (struct inode *);
- +extern void supermount_put_inode (struct inode *);
- +extern int supermount_permission (struct inode *, int mask);
- +
- +/* namei.c */
- +extern void supermount_release (struct inode *, struct file *);
- +extern int supermount_lookup (struct inode *,const char *, int, struct inode **);
- +extern int supermount_create (struct inode *,const char *, int, int,
- + struct inode **);
- +extern int supermount_mkdir (struct inode *, const char *, int, int);
- +extern int supermount_rmdir (struct inode *, const char *, int);
- +extern int supermount_unlink (struct inode *, const char *, int);
- +extern int supermount_symlink (struct inode *, const char *, int, const char *);
- +extern int supermount_link (struct inode *, struct inode *, const char *, int);
- +extern int supermount_mknod (struct inode *, const char *, int, int, int);
- +extern int supermount_rename (struct inode *, const char *, int,
- + struct inode *, const char *, int, int);
- +
- +/* super.c */
- +extern void supermount_error (struct super_block *, const char *, const char *, ...)
- + __attribute__ ((format (printf, 3, 4)));
- +extern NORET_TYPE void supermount_panic (struct super_block *, const char *,
- + const char *, ...)
- + __attribute__ ((NORET_AND format (printf, 3, 4)));
- +extern void supermount_warning (struct super_block *, const char *, const char *, ...)
- + __attribute__ ((format (printf, 3, 4)));
- +extern void supermount_put_super (struct super_block *);
- +extern void supermount_write_super (struct super_block *);
- +extern int supermount_remount (struct super_block *, int *, char *);
- +extern struct super_block * supermount_read_super (struct super_block *,void *,int);
- +extern void supermount_statfs (struct super_block *, struct statfs *, int);
- +extern int supermount_media_check (struct super_block *);
- +extern int supermount_check_inode (struct inode *);
- +
- +/* dir.c */
- +extern struct inode_operations supermount_dir_iops;
- +extern struct inode_operations supermount_root_iops;
- +
- +/* inode.c */
- +extern struct inode_shadow_operations supermount_shadow_iops;
- +
- +/* file.c */
- +/* extern struct inode_operations supermount_shadow_file_iops; */
- +
- +/* symlink.c */
- +extern struct inode_operations supermount_symlink_iops;
- +
- +#endif /* __KERNEL__ */
- +
- +#endif /* _LINUX_SUPERMOUNT_FS_H */
- Index: linux/include/linux/supermount_fs_i.h
- diff -u linux/include/linux/supermount_fs_i.h:1.1 linux/include/linux/supermount_fs_i.h:1.1.4.1
- --- linux/include/linux/supermount_fs_i.h:1.1 Mon Feb 26 17:55:22 1996
- +++ linux/include/linux/supermount_fs_i.h Sat Nov 9 17:27:49 1996
- @@ -0,0 +1,23 @@
- +/*
- + * linux/include/linux/supermount_fs.h
- + *
- + * In-core inode structure for the dynamic remounting of removable media
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + */
- +
- +#ifndef _LINUX_SUPERMOUNT_FS_I_H
- +#define _LINUX_SUPERMOUNT_FS_I_H
- +
- +struct supermount_inode_info {
- + struct inode * i_hidden;
- + int i_sb_version;
- + int i_subino;
- + int i_counted;/* Has this inode been counted in
- + the superblock reference counts
- + yet? */
- +};
- +
- +#endif /* _LINUX_SUPERMOUNT_FS_I_H */
- Index: linux/include/linux/supermount_fs_sb.h
- diff -u linux/include/linux/supermount_fs_sb.h:1.1 linux/include/linux/supermount_fs_sb.h:1.1.4.1
- --- linux/include/linux/supermount_fs_sb.h:1.1 Mon Feb 26 17:55:22 1996
- +++ linux/include/linux/supermount_fs_sb.h Sat Nov 9 17:27:49 1996
- @@ -0,0 +1,44 @@
- +/*
- + * linux/include/linux/supermount_sb_fs.h
- + *
- + * In-core superblock struct for the dynamic remounting of removable media
- + *
- + * Copyright (C) 1995
- + * Stephen Tweedie (sct@dcs.ed.ac.uk)
- + *
- + */
- +
- +#ifndef _LINUX_SUPERMOUNT_FS_SB_H
- +#define _LINUX_SUPERMOUNT_FS_SB_H
- +
- +typedef enum {
- + SUPERMOUNT_UNMOUNTED, /* No media mounted */
- + SUPERMOUNT_SUSPENDED, /* Mounted but suspended because
- + no files open */
- + SUPERMOUNT_ONLINE, /* Mounted and active */
- +} sm_state_t;
- +
- +/*
- + * supermount super-block data in memory
- + */
- +struct supermount_sb_info {
- + sm_state_t s_state;
- + int s_version; /* Used to indicate obsolete inodes */
- + mode_t s_default_mode; /* Default mode for supermount root */
- +
- + const char * s_type; /* Type of fs to be sub-mounted */
- + const char * s_devname; /* Where to mount the subfs */
- + int s_mflags; /* Flags to pass when mounting subfs */
- + const char * s_data; /* Data to pass when mounting subfs */
- +
- + struct inode * s_undermount; /* Mount point for subfs */
- + struct super_block * s_subfs; /* The submounted fs sb */
- + int s_opencount; /* Refcount of opened inodes
- + (an inode in use as cwd
- + does not count as open) */
- +
- + /* Flags */
- + int s_dirty : 1; /* Do we need to fsync() the subfs? */
- +};
- +
- +#endif /* _LINUX_SUPERMOUNT_FS_SB_H */
-